﻿
/***更新****************************************************************   
*       最后更新 : ZhangJunhua   
*       更新日期 : 2010/04/15   
*       更新目的 : 增加  功能；修复bug   
*       更新版本 : 1.00   
*       更新日志 : 日志   
************************************************************************/     
  
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;
using System.IO;

namespace System.Windows.Media
{
    public class SaveAsImage
    {
        /// <summary>
        /// Get image MemoryStream from WriteableBitmap
        /// </summary>
        /// <param name="bitmap">WriteableBitmap</param>
        /// <returns>MemoryStream</returns>
        /// 
        
        public static void SaveToImage(UIElement uie, double dScale = 1.0)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "Bitmap Images|*.bmp";
            if (sfd.ShowDialog().Value)
            {
                Stream stream = sfd.OpenFile();
                ScaleTransform sclt = new ScaleTransform();
                sclt.ScaleY =
                sclt.ScaleX = dScale;
                WriteableBitmap bmp = new WriteableBitmap(uie, sclt);
                byte[] header = new byte[54];
                // B
                header[0] = 0x42;
                // M
                header[1] = 0x4D;
                // Padding for 4 byte alignment (Could be a value other than zero).
                int padding = bmp.PixelWidth % 4;
                byte[] paddingData = new byte[padding];
                // Calculate the size of the bitmap. Note the data is stored in the reverse order in any binary file.
                int size = bmp.Pixels.Length * 3 + 54 + padding * bmp.PixelHeight;
                Write4ByteBinaryData(header, 2, size);
                // The offset where the bitmap data (pixels) can be found.
                Write4ByteBinaryData(header, 10, 54);
                // The number of bytes in the header (from this point).
                Write4ByteBinaryData(header, 14, 40);
                // The width and height of the bitmap in pixels
                Write4ByteBinaryData(header, 18, bmp.PixelWidth);
                Write4ByteBinaryData(header, 22, bmp.PixelHeight);
                // 1 plane being used.
                header[26] = 1;
                // The number of bits/pixel is 24. We do not take alpha into account.
                Write2ByteBinaryData(header, 28, 24);
                //The size of the raw BMP data (after this header)
                Write4ByteBinaryData(header, 34, 16);
                // The horizontal resolution of the image. 96 per inch is 3780 per meter.
                Write4ByteBinaryData(header, 38, 3780);
                // The vertical resolution of the image.
                Write4ByteBinaryData(header, 42, 3780);
                stream.Write(header, 0, 54);                

                for (int i = bmp.PixelHeight-1; i >-1 ; i--)
                {
                    for (int j = 0; j < bmp.PixelWidth; j++)
                    {
                        int pixel = bmp.Pixels[i * bmp.PixelWidth + j];
                        stream.WriteByte((byte)(pixel << 24 >> 24));
                        stream.WriteByte((byte)(pixel << 16 >> 24));
                        stream.WriteByte((byte)(pixel << 8 >> 24));
                    }
                    stream.Write(paddingData, 0, padding);
                }
                stream.Close();
            }
        }

        /// <summary>
        /// Write the next 2 bytes with the integer data.
        /// </summary>
        private static void Write2ByteBinaryData(byte[] header, int start, int data)
        {
            header[start] = (byte)(data << 24 >> 24);
            header[start + 1] = (byte)(data << 16 >> 24);
        }

        /// <summary>
        /// Write the next 4 bytes with the integer data.
        /// </summary>
        private static void Write4ByteBinaryData(byte[] header, int start, int data)
        {
            header[start] = (byte)(data << 24 >> 24);
            header[start + 1] = (byte)(data << 16 >> 24);
            header[start + 2] = (byte)(data << 8 >> 24);
            header[start + 3] = (byte)(data >> 24);
        }

    }
}
